package liming.tool.handle;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * FileRW类用于文件读写操作，提供了多种编码格式和读写方式。
 * 包括读取文本文件、写入文本文件、将错误信息的堆栈数据转为文本显示、读取文件并将二进制数据转为字符串、将文件从一个地方转移到另一个地方、将字符串转为二进制数据并写入文件、复制大文件等功能。
 * 枚举类型FileRW表示文件编码格式，提供了多种编码格式可供选择。
 * CODE表示当前编码格式，可以通过setCode方法设置编码格式。
 * readString方法用于读取文本文件，返回文件内容。
 * WriteString方法用于写入文本文件，可以选择覆盖或追加写入。
 * getError方法用于将错误信息的堆栈数据转为文本显示，返回错误信息字符串。
 * readFile方法用于读取文件并将二进制数据转为字符串。
 * writeFile方法用于将字符串转为二进制数据并写入文件，可以选择追加或覆盖写入。
 * transferFiles方法用于将文件从一个地方转移到另一个地方。
 * copyLargeFile方法用于复制大文件。
 */
public class FileRW {
    private static FileUnit ENCODE = FileUnit.UTF8;

    public static FileUnit getFileRW(int num) throws EOFException {
        switch (num) {
            case 0:
                return FileUnit.UTF8;
            case 1:
                return FileUnit.GBK;
            case 2:
                return FileUnit.GB2312;
            case 3:
                return FileUnit.GB18030;
            case 4:
                return FileUnit.ISO88591;
            case 5:
                return FileUnit.UTF16;
            default:
                throw new EOFException("未找到id为 " + num + " 的方法");
        }
    }

    public static FileUnit getFileRW(String name) throws EOFException {
        switch (name) {
            case "UTF-8":
                return FileUnit.UTF8;
            case "GBK":
                return FileUnit.GBK;
            case "GB2312":
                return FileUnit.GB2312;
            case "GB18030":
                return FileUnit.GB18030;
            case "ISO-8859-1":
                return FileUnit.ISO88591;
            case "UTF-16":
                return FileUnit.UTF16;
            default:
                throw new EOFException("未找到name为 " + name + " 的方法");
        }
    }

    /**
     * 设置编码格式
     */
    public static String setEnCode(FileUnit unit) {
        ENCODE = unit;
        return ENCODE.value;
    }

    public static String getEnCode() {
        return ENCODE.value;
    }

    /**
     * 读取文件，对文本文件读取
     *
     * @param file 目标文件
     * @return 文件内容
     */
    public static String readFileString(File file) throws IOException {
        return readFileString(file, ENCODE);
    }

    public static String readFileString(File file, FileUnit unit) throws IOException {
        BufferedReader bReader = new BufferedReader(new InputStreamReader(Files.newInputStream(file.toPath()), unit.value));// new一个BufferedReader对象，将文件内容读取到缓存
        StringBuilder sb = new StringBuilder();// 定义一个字符串缓存，将字符串存放缓存中
        String s;
        while ((s = bReader.readLine()) != null) {// 逐行读取文件内容，不读取换行符和末尾的空格
            sb.append(s).append("\n");// 将读取的字符串添加换行符后累加存放在缓存中
        }
        bReader.close();
        return sb.toString();
    }

    /**
     * 写入文件，采用覆盖的方式
     *
     * @param file   目标文件
     * @param code   写入内容
     * @param append 是否追加写入
     * @return 写入结果
     */
    public static boolean writeFileString(File file, String code, boolean append) throws IOException {
        return writeFileString(file, code, append, ENCODE);
    }

    public static boolean writeFileString(File file, String code, boolean append, FileUnit unit) throws IOException {
        OutputStreamWriter oStreamWriter = new OutputStreamWriter(new FileOutputStream(file, append), unit.value);
        oStreamWriter.append(code);
        oStreamWriter.close();
        return true;
    }

    public static byte[] readFileByte(File file) {
        try {
            if (file.length() > Integer.MAX_VALUE)
                throw new RuntimeException("文件大小超过限制" + file.length() + ":" + Integer.MAX_VALUE
                        + "，若本地复制文件请使用transferFiles(old-filepath,new-filepath)");
            FileInputStream fis = new FileInputStream(file);
            byte[] data = new byte[(int) file.length()];
            fis.read(data);
            fis.close();
            return data;
        } catch (Exception e) {
            System.out.println(getError(e));
            return null;
        }
    }

    // 将二进制数据写入文件，通过设置append的值选择是否追加写入
    public static boolean writeFileByte(File file, byte[] data, boolean append) {
        try {
            FileOutputStream fos = new FileOutputStream(file, append);
            fos.write(data);
            fos.flush();
            fos.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * @param sourceFile 目标文件
     * @param destFile   新文件
     */
    public static void copyLargeFile(File sourceFile, File destFile) throws IOException {
        Path sourcePath = Paths.get(sourceFile.getPath());
        Path destPath = Paths.get(destFile.getPath());
        Files.copy(sourcePath, destPath);
    }

    /**
     * 将错误信息的堆栈数据转为文本显示
     */
    public static String getError(Exception e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }

    public static String getError(Error e) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        e.printStackTrace(pw);
        return sw.toString();
    }

    public enum FileUnit {
        UTF8("UTF-8", 0),
        GBK("GBK", 1),
        GB2312("GB2312", 2),
        GB18030("GB18030", 3),
        ISO88591("ISO-8859-1", 4),
        UTF16("UTF-16", 5);
        private final String value;
        private final int num;

        FileUnit(String value, int num) {
            this.value = value;
            this.num = num;
        }

        public String getValue() {
            return value;
        }

        public byte getNum() {
            return (byte) num;
        }
    }
}
